// --- 记录类 ---

/*
使用String、Integer等类型的时候,这些类型都是不变类,一个不变类具有以下特点:
	1.定义class的时候使用final,无法派生子类
	2.每个字段都使用了final,保证创建后无法被修改
*/

//假设：我们希望定义一个Point类,有x、y两个变量,同时它是一个不变类,可以这么写
public final class Point {
	private final int x;
	private final int y;

	public Point(int x, int y) {
		this.x = x;
		this.y = y;
	}

	public int x() {
		return this.x;
	}

	public int y() {
		return this.y;
	}
}

//为了保证'不变类'的【比较】,还需要正确覆写equals()和hashCode()方法,这样才能在集合类中保证正常使用。后续会详细讲解equals()和hashCode(),这里演示Point不变类的写法目的是,这些代码写起来都比较简单,但却非常繁琐




// # record #
//从Java 14开始,引入了新的Record类。我们定义Record类的时候,使用关键字record。把上述class Point 改写成 record Point
public record Point(int x, int y) {}

public class Main {
	public static void main(String[] args) {
		Point p = new Point(123,456);

		SYstem.out.println(p.x());
		System.out.println(p.y());
		System.out.println(p);
	}
}

//仔细观察 Point的定义:
public record Point(int x, int y) {}

//把上述定义改写为class,相当于以下代码：
public final class Point extends Record {
    private final int x;
    private final int y;

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public int x() {
        return this.x;
    }

    public int y() {
        return this.y;
    }

    public String toString() {
        return String.format("Point[x=%s, y=%s]", x, y);
    }

    public boolean equals(Object o) {
        //...
    }
    public int hashCode() {
        //...
    }
}
/*
除了用final修饰class以及每个field外、编译器还自动为我们创建了 构造方法、field同名的方法、覆写toString()、equals()、hashCode() 这5大类核心部件

换句话说,使用record代替class做关键字,可以一行写出一个‘不变类’

和enum类似,我们自己不能直接从Record派生,只能通过record关键字,由编译器实现继承
*/



// # 构造方法 # 
/*
编译器默认按照record声明的变量顺序自动创建一个构造方法,并在方法内给field赋值。那么,假如我们要检查参数,应该怎么办?
*/

//假设Point类的x、y不允许负数,我们就得给Point的构造方法加上检查逻辑：
public record Point(int x, int y) {
	public Point {
		if (x < 0 || y < 0) {
			throw new IllegalArgumentException();
		}
	}
}

//注意到方法public Point {...}被称为Compact Constructor,它的目的是让我们编写部分代码,用于自定义检查逻辑,编译器根据上面部分最终生成的构造方法如下:
public final class Point extends Record {
    public Point(int x, int y) {
        // 这是我们编写的Compact Constructor:
        if (x < 0 || y < 0) {
            throw new IllegalArgumentException();
        }
        // 这是编译器继续生成的赋值代码:
        this.x = x;
        this.y = y;
    }
    ...
}

//作为record的Point仍然可以添加静态方法。一种常用的静态方法是of()方法，用来创建‘一个新的Point Instance’：
public record Point(int x, int y) {
	public static Point of() { 
		return new Point(0, 0);
	}

	public static Point of(int x, int y){
		return new Point(x, y);
	}
}

//这样我们可以写出更加简洁的代码
var z = Point.of();
var p = Point.of(123,456);



/* --- record(记录类)の小结 ---

1.从Java 14开始,提供新的record关键字,可以非常方便地定义Data Class:
	1.使用record定义‘不变类’

	2.可以通过编写Compact Constructor(袖珍的、紧凑的构造器/契约构造器)的代码对参数进行自定义验证

	3.可以定义‘静态方法’


使用record需要开启Java 14特性:
	Preferences - Java - Compiler:

	Compiler compliance level: 14

	钩上

	☑︎Use ‘--release’ option

	☑︎Enable preview features for Java 14

*/